﻿#include "AVVideoConvert.h"
#include <QDebug>

extern "C"
{
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
};

AVVideoConvert::AVVideoConvert() : QObject(0){}

AVFrame *AVVideoConvert::convertToFrame(const VDFrame *frame)
{
    int width = frame->width;
    int height = frame->height;
    AVPixelFormat srcFormat,dstFormat;
    switch (frame->format) {
    case FDJ_AVCOLOR_FORMAT_I420:
        srcFormat = AV_PIX_FMT_YUV420P;
        break;
    case FDJ_AVCOLOR_FORMAT_NV21:
        srcFormat = AV_PIX_FMT_NV12;
        break;
    case FDJ_AVCOLOR_FORMAT_NV12:
        srcFormat = AV_PIX_FMT_NV12;
        break;

    case FDJ_AVCOLOR_FORMAT_RGBA:
        srcFormat = AV_PIX_FMT_ARGB;
        break;

    case FDJ_AVCOLOR_FORMAT_RGB24:
        srcFormat = AV_PIX_FMT_BGR24;
        break;
    default:
        qDebug() << "type error";
        exit(0);
        break;
    }

    dstFormat = AV_PIX_FMT_YUV420P;

    struct SwsContext * m_img_convert_ctx = sws_getContext(width, height, srcFormat,
                                                           width, height, dstFormat, SWS_BICUBIC, NULL, NULL, NULL);

    AVFrame * srcFrame = av_frame_alloc();
    srcFrame->format = srcFormat;
    srcFrame->width = width;
    srcFrame->height = height;

    av_frame_get_buffer(srcFrame,32);
    av_image_fill_arrays(srcFrame->data,srcFrame->linesize,(uint8_t*)frame->buffer,dstFormat,width,height,1);

    AVFrame *yuvFrame = av_frame_alloc();
    yuvFrame->format = dstFormat;
    yuvFrame->width = width;
    yuvFrame->height = height;

    // alloc yuv frame
    av_frame_get_buffer(yuvFrame, 32);
    sws_scale(m_img_convert_ctx,(const uint8_t* const*)srcFrame->data, srcFrame->linesize, 0, height, yuvFrame->data, yuvFrame->linesize);

    av_frame_unref(srcFrame);
    av_frame_free(&srcFrame);
    sws_freeContext(m_img_convert_ctx);

    return yuvFrame;
}


AVFrame* AVVideoConvert::convertToFrame(const QVideoFrame &frame,QVideoFrame::PixelFormat _dstFormat)
{
    int width = frame.width();
    int height = frame.height();
    AVPixelFormat srcFormat,dstFromat;
    switch (frame.pixelFormat()) {
    case QVideoFrame::Format_RGB32:
        srcFormat = AV_PIX_FMT_BGRA;
        break;

        // may in mac
    case QVideoFrame::Format_UYVY:
        srcFormat = AV_PIX_FMT_UYVY422;
        break;
    case QVideoFrame::Format_YUYV:
        srcFormat = AV_PIX_FMT_YUYV422;
        break;
    case QVideoFrame::Format_NV12:
        srcFormat = AV_PIX_FMT_NV12;
        break;

    case QVideoFrame::Format_BGRA32:
        srcFormat = AV_PIX_FMT_ARGB;
        break;
    default:
        qDebug() << "type error";
        exit(0);
        break;
    }

    switch (_dstFormat) {
    case QVideoFrame::Format_YUV420P:
        dstFromat = AV_PIX_FMT_YUV420P;
        break;
    default:
        qDebug() << "type error";
        exit(0);
        break;
    }

    struct SwsContext * m_img_convert_ctx = sws_getContext(width, height, srcFormat,
                                                           width, height, dstFromat, SWS_BICUBIC, NULL, NULL, NULL);

#ifdef WIN32
    AVFrame * srcFrame = av_frame_alloc();
    srcFrame->format = srcFormat;
    srcFrame->width = width;
    srcFrame->height = height;
    srcFrame->data[0] = (uint8_t*)frame.bits();
    srcFrame->linesize[0] = frame.size().width() * 4;//对于音频，这个参数可能是数据的总长度，但是对于图像则不是这样
#else
    AVFrame * srcFrame = av_frame_alloc();
    srcFrame->format = srcFormat;
    srcFrame->width = width;
    srcFrame->height = height;
    srcFrame->data[0] = (uint8_t*)frame.bits();
    srcFrame->data[1] = (uint8_t*)frame.bits(1);
    srcFrame->data[2] = (uint8_t*)frame.bits(2);
    srcFrame->linesize[0] = frame.bytesPerLine(0);
    srcFrame->linesize[1] = frame.bytesPerLine(1);
    srcFrame->linesize[2] = frame.bytesPerLine(2);
#endif

    AVFrame *yuvFrame = av_frame_alloc();
    yuvFrame->format = dstFromat;
    yuvFrame->width = width;
    yuvFrame->height = height;

    //分配yuv空间
    av_frame_get_buffer(yuvFrame, 32);
    sws_scale(m_img_convert_ctx,(const uint8_t* const*)srcFrame->data, srcFrame->linesize, 0, height, yuvFrame->data, yuvFrame->linesize);

    av_frame_free(&srcFrame);
    sws_freeContext(m_img_convert_ctx);

    return yuvFrame;
}

AVFrame *AVVideoConvert::convertToFrame(const QImage &image)
{
    int width = image.width();
    int height = image.height();

    AVPixelFormat srcFormat,dstFromat;

    dstFromat = AV_PIX_FMT_YUV420P;

    float rate = 3;
    switch (image.format()) {
    case QImage::Format_RGB32:
        srcFormat = AV_PIX_FMT_BGRA;
        rate = 4;
        break;
    case QImage::Format_Indexed8:
        srcFormat = AV_PIX_FMT_RGB4_BYTE;
        rate = 1;
        break;
    default:
        qDebug() << "error" << image.format();
        break;
    }

    struct SwsContext * m_img_convert_ctx = sws_getContext(width, height, srcFormat,
                                                           width, height, dstFromat, SWS_BICUBIC, NULL, NULL, NULL);

    AVFrame * srcFrame = av_frame_alloc();
    srcFrame->format = srcFormat;
    srcFrame->width = image.width();
    srcFrame->height = image.height();

    srcFrame->data[0] = (uint8_t*)image.bits();
    srcFrame->linesize[0] = image.width() * rate;//对于音频，这个参数可能是数据的总长度，但是对于图像则不是这样

    AVFrame * yuvFrame = av_frame_alloc();
    yuvFrame->format = dstFromat;
    yuvFrame->width = image.width();
    yuvFrame->height = image.height();

    av_frame_get_buffer(yuvFrame,32);

    sws_scale(m_img_convert_ctx,(const uint8_t* const*)srcFrame->data, srcFrame->linesize, 0, height, yuvFrame->data, yuvFrame->linesize);

    av_frame_free(&srcFrame);
    sws_freeContext(m_img_convert_ctx);

    return yuvFrame;
}

